use cache::{init_cache, ResourceCache};
/**
 * 这里仅仅实现了一个单线程的HTTP服务器
 * 及其简单，只能处理GET请求，并且只处理HTTP/1.1 GET / 和favicon.ico的请求
 *
 * 要完成这样的一个程序并不容易。除了要熟悉基本的内容，还要
 * 1.熟悉rust的常见的api  ，可以参考 https://doc.rust-lang.org/中的api资料
 * 2.记住各种奇奇怪怪的unwrap()
 * 3.理解for循环和迭代器，以及模式匹配所造成的一些困扰
 */
use chrono::Local;
use keyboard::Keyboard;
use std::{
    fs,
    io::{prelude::*, BufReader},
    net::{TcpListener, TcpStream},
    path::Path,
    sync::{Arc, Mutex, OnceLock},
    thread,
    time::Duration,
};
use threadpool::ThreadPool;

static COUNTER: OnceLock<Arc<Mutex<u32>>> = OnceLock::new();

/**
 * 从这里读取客户端的请求头，然后根据请求头的某些信息来做不同的处理
 */
fn get_agent(headers: &Vec<String>) -> String {
    let mut user_agent = String::new();
    for line in headers {
        if line.starts_with("User-Agent") {
            user_agent = line.to_string();
            //判断user_agent是否包含FireFox
            if user_agent.contains("Firefox") {
                user_agent = "Firefox".to_string();
            } else if user_agent.contains("Edg") {
                user_agent = "Edge".to_string();
            } else if user_agent.contains("OPR") {
                user_agent = "OPR".to_string();
            }
            else if user_agent.contains("Chrome") {
                user_agent = "Chrome".to_string();
            } 
            else{
                user_agent = "Other".to_string();
            }
            break;
        }
    }
    user_agent
}

/**
 * 读取请求头的所有内容，并以字符串数组的形式返回。
 */
fn read_header(stream: &mut TcpStream) -> Vec<String> {
    let buf_reader = BufReader::new(stream);
    let http_request: Vec<String> = buf_reader
        .lines()
        .map(|result| result.unwrap())
        .take_while(|line| !line.is_empty())
        .collect();
    return http_request;
}

fn main() {
    COUNTER.get_or_init(|| Arc::new(Mutex::new(0)));
    init_cache();
    //初始化键盘
    let kb = Keyboard::new();
    let pool = Arc::new(ThreadPool::new(10));
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();

    println!("服务器在 127.0.0.1:7878 启动 ❤🌼");
    println!("按下 Ctrl+C 以停止服务器");
    while !kb.is_ctrl_c_pressed() {
        match listener.accept() {
            Ok((mut stream, _)) => {
                pool.execute(move || {
                    response_ifhttpreq(&mut stream);
                });
            }
            Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
                thread::sleep(Duration::from_millis(100));
                continue;
            }
            Err(e) => {
                eprintln!("Error accepting connection: {}", e);
                break;
            }
        }
    }
    println!("\n\rServer shutting down gracefully...");
}

fn inc_counter() -> u32 {
    let cc = COUNTER.get().unwrap().clone();
    let mut currnet_counter = cc.lock().unwrap();
    *currnet_counter += 1;
    *currnet_counter
}

/**
 * 极其简单的响应
 * 当请求为HTTP/1.1 GET / 时才返回hello.html的内容
 * 当请求为GET /favicon.ico HTTP/1.1 时返回favicon.ico的内容
 */
fn response_ifhttpreq(stream: &mut TcpStream) {
    //这里故意每次处理都等待1秒钟
    //以便放大单线程下的阻塞问题，便于观察效果
    println!("正在接收数据...");
    //打印当前时间，精确到毫秒
    let current_counter = inc_counter();
    let human_readable_time = Local::now().format("%Y-%m-%d %H:%M:%S%.3f").to_string();
    let headers: Vec<String> = read_header(stream);
    if headers.len() == 0 {
        println!("第{}次接收时间: {}", current_counter, human_readable_time);
        handle_404(stream);
        return;
    } else {
        let user_agent = get_agent(&headers);
        println!("第{}次接收时间: {} {}\n\r", current_counter, human_readable_time,user_agent);
        let param = headers[0].as_str();
        if param == "GET / HTTP/1.1" {
            //显示首页
            handle_root(stream);
        } else if param == "GET /favicon.ico HTTP/1.1" {
            //显示favicon.ico图标
            handle_favicon(stream);
        } else {
            // 其它请求都返回404错误
            handle_404(stream);
        }
    }
}

/**
 * 处理根目录请求
 */
fn handle_root(stream: &mut TcpStream) {
    let status_line = "HTTP/1.1 200 OK";

    let cache_html = ResourceCache::get_cache_html("hello.html");
    match cache_html {
        Some(html) => {
            println!("从缓存中获取hello.html");
            let response = format!("{status_line}\r\n\r\n{html}");
            stream.write_all(response.as_bytes()).unwrap();
            return;
        }
        None => {}
    }
    println!("从文件系统读取hello.html");
    let contents = fs::read_to_string("hello.html").unwrap();
    let response = format!("{status_line}\r\n\r\n{contents}");
    stream.write_all(response.as_bytes()).unwrap();
    println!("html写入缓存中...");
    ResourceCache::set_cache_html("hello.html", contents);
}
/**
 * 处理404错误
 */
fn handle_404(stream: &mut TcpStream) {
    let response = "HTTP/1.1 404 NOT FOUND\r\n\
                    Content-Length: 0\r\n\
                    \r\n";
    stream.write_all(response.as_bytes()).unwrap();
}

/**
 * 处理favicon.ico请求
 */
fn handle_favicon(stream: &mut TcpStream) {
    let image = ResourceCache::get_cache_image("favicon.ico");
    match image {
        Some(bytes) => {
            println!("从缓存中获取favicon.ico");
            let mut response = format!(
                "HTTP/1.1 200 OK\r\n\
                Content-Type: image/x-icon\r\n\
                Content-Length: {}\r\n\
                \r\n",
                bytes.len()
            )
            .into_bytes();
            response.extend(&bytes);
            stream.write_all(&response).unwrap();
            stream.flush().unwrap();
            return;
        }
        None => {}
    }
    // 读取 favicon.ico 文件
    println!("从文件系统读取favicon.ico");
    let favicon_path = Path::new("favicon.ico");
    match fs::read(favicon_path) {
        Ok(favicon_data) => {
            // 构造并发送完整HTTP响应
            let mut response = format!(
                "HTTP/1.1 200 OK\r\n\
                Content-Type: image/x-icon\r\n\
                Content-Length: {}\r\n\
                \r\n",
                favicon_data.len()
            )
            .into_bytes();
            response.extend(&favicon_data);
            stream.write_all(&response).unwrap();
            stream.flush().unwrap();
            println!("favicon写入缓存中...");
            ResourceCache::set_cache_image("favicon.ico", favicon_data);
        }
        Err(_) => {
            // 如果图标文件不存在，返回 404
            let response = "HTTP/1.1 404 NOT FOUND\r\n\
                    Content-Length: 0\r\n\
                    \r\n";
            stream.write_all(response.as_bytes()).unwrap();
            stream.flush().unwrap();
        }
    }
}
